;; =======================================================
;; this only works on earth based computer, not exo planetary one:
;; 
(use-modules (srfi srfi-9))


(define-record-type <peano-zero>
  (peano-zero)
  peano-zero?)


(define-record-type <peano-successor>
  (peano-successor predecessor)
  peano-successor?
  (predecessor peano-predecessor))

(define (pdec n)
  (peano-predecessor n))

(define (pinc n)
  (peano-successor n))

(define (number->peano-number num)
  (cond ((= num 0) (peano-zero))
        ((> num 0) (peano-successor (number->peano-number (1- num))))
        (else (error "not an integer" num))))


(define (peano-number->number pn)
  (cond ((peano-zero? pn) 0)
        ((peano-successor? pn) (+ (peano-number->number (peano-predecessor pn)) 1))
        (else (error "not a peano number" pn))))

;;(integer->peano-number 2)

;;(peano-number->number (number->peano-number 6))

;;(peano-zero? zero)

(define (peano-add-iterative x y)
  (if (peano-zero? x)
      y
      (peano-add-iterative (pdec x)
                           (pinc y))))


(define (peano-add-recursive x y)
  (display "peano-add-recursive\n")
  (if (peano-zero? x)
      y
      (pinc (peano-add-recursive (pdec x)
                                 y))))

(define peano-add peano-add-iterative)

" We want to multiply. We can not make use of any 'patterns' in the
numbers (like decimal digits) as there are none in the peano number
representation. What can we do?

We can only ever know directly (immediately, i.e. in 1 step) whether a peano
number is zero (peano-zero?) or not (peano-successor?).

If x is a zero, the multiplication of x with y is  zero.
                ------------------------------
The multiplication of x with y  is   [We define the multiplication of x with y as:  ]
   - zero if x is zero
   - ..... if x is not zero
"
(define (peano-mul-recursive x y) ;; 10 20
  ;; XX optimize
  (if (peano-zero? x)
      zero
      ;; 9 * 20 = 180
      (peano-add y (peano-mul-recursive (pdec x) y))))


;;(s:peano-mul-recursive 5 5)


'(define (peano-mul-iterative-helper x y res)
  (if (peano-zero? x)
      res
      (peano-mul-iterative-helper )))

'(define (peano-mul-iterative x y)
  (peano-mul-iterative-helper x y zero))

;; ------------------------------------------------------------------
(define (s:peano-add-iterative x y)
  (peano-number->number (peano-iterative (number->peano-number x)
                                         (number->peano-number y))))

;;(s:peano-add-iterative 1 1)

(define (s:peano-add-recursive x y)
  (peano-number->number (peano-add-recursive (number->peano-number x)
                                             (number->peano-number y))))

;;(s:peano-add-recursive 1 1)

(define (s:peano-mul-recursive x y)
  (peano-number->number (peano-mul-recursive (number->peano-number x)
                                             (number->peano-number y))))


;; -----
(define (s:peano-add kind x y)
  (peano-number->number ((case kind
                           ((#:rec) peano-add-recursive)
                           ((#:iter) peano-add-iterative))
                         (number->peano-number x)
                         (number->peano-number y))))

;; (s:peano-add #:rec 10 13)

;; (0 1 2 3 4 5 6 7 8 9 10 11)
;; (11 0 1 2 3 4 5 6 7 8 9 10)


 ;; ------------------------------------------------------------------

 (define average (lambda (v1 v2) (/ (+ v1 v2) 2)))

(define square (lambda (n) (* n n)))

(define (sqrt n)
  (define (improve guess)
    (average guess (/ n guess)))
  (define (good-enough? guess)
    (< (abs (- (square guess) n)) 0.0000000001))
  (define (tryit guess)
    (if (good-enough? guess)
        guess
        (tryit (improve guess))))
  (tryit 1))

(sqrt 25)








;; (define (peano-recursive x y)
;;   (if (= x 0)
;;       y
;;       (1+ (peano-recursive (1- x) y))))

;; (peano-iterative 1 1)

;; (peano-predecessor two)

;; (peano-successor one)


;; (define (peano-iterative-addition x y)
;;   (cond ((peano-zero? (integer->peano-number x)) y)
;;         ((peano-successor? x) (peano-iterative-addition (peano-predecessor (integer->peano-number x))
;;                                                         (peano-successor (integer->peano-number y))))))

;;(peano-iterative-addition 1 1)

(define (peano-iterative-addition x y)
  (cond ((peano-zero? (integer->peano-number x))
         y)
        ((peano-successor? x)
         (peano-iterative-addition (peano-predecessor (integer->peano-number x))
                                   (peano-successor (integer->peano-number y))))))

;; (define (peano-iterative-addition x y)
;;   (if (peano-zero? (integer->peano-number x))
;;       y
;;       (peano-iterative-addition (peano-predecessor (integer->peano-number x)) (peano-successor (integer->peano-number y)))))

;;(peano-iterative-addition 1 1)

(define (peano-iterative-addition px py)
  (if (= px zero)
      py
      (peano-iterative-addition (dec (peano-number->number px)) (1+ (peano-number->number py)))))

;; (peano-iterative-addition one one)

;; (peano-iterative 1 1)



;; here I'm just converting at the end to a peano-number after doing the addition with integers
(define (peano-iterative x y)
  (if (zero? x)
      (integer->peano-number y)
      (peano-iterative (1- x) (1+ y))))

;; (peano-iterative 5 5)

;; (peano-predecessor two)

;; (peano-iterative one one)

(define (make-traced f)
  (lambda args
    (display "calling (")
    (display f)
    (for-each (lambda (arg)
                (display " ")
                (display arg))
              args)
    (display ")\n")
    (let ((res (apply f args)))
      (display "= ")
      (display res)
      (newline)
      res)))

;; (define peano-predecessor* (make-traced peano-predecessor))


;; (use-modules (ice-9 debugging trace))

;; (trace peano-predecessor)

(define-syntax update!
  (syntax-rules ()
    ((_ v fn)
     (set! v (fn v)))))

(define-syntax peano-dec!
  (syntax-rules ()
    ((_ v)
     (set! v (peano-predecessor v)))))

;; (+ 5 5)

(define zero
  (peano-zero))

(define one
  (peano-successor zero))

(define two
  (peano-successor (peano-successor zero)))

(define five
  (peano-successor (peano-successor (peano-successor (peano-successor (peano-successor zero))))))

(define (dec n)
  (1- n))

(define (inc n)
  (1+ n))
